/**
 * Project Name:pay-demo
 * File Name:RSAUtil.java
 * Package Name:com.pay.util
 * Date:2018年7月4日下午3:50:49
 * Copyright (c) 2018, www.zengfull.com All Rights Reserved.
 *
*/

package com.xyy.saas.payment.util;

import org.bouncycastle.jce.provider.BouncyCastleProvider;

import javax.crypto.Cipher;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.math.BigInteger;
import java.security.*;
import java.security.spec.PKCS8EncodedKeySpec;
import java.security.spec.X509EncodedKeySpec;

public class RSAUtil {
	public static final String SIGN_SHA256_WITH_RSA = "SHA256WithRSA";
	public static final String SIGN_SHA1_WITH_RSA = "SHA1WithRSA";
	public static final String KEY_ALGORITHM = "RSA";//加密算法
	private static final int MAX_ENCRYPT_BLOCK = 117;// RSA加密明文大小
	private static final int MAX_DECRYPT_BLOCK = 128;// RSA解密密文大小

	static{
		if (Security.getProvider(BouncyCastleProvider.PROVIDER_NAME) == null){
			Security.addProvider(new BouncyCastleProvider());
		}
	}

	/**
	 * 公钥加密 RSA/ECB/PKCS1Padding 填充方式
	 * @param data
	 * @param publicKey
	 * @return
	 * @throws Exception
	 */
	public static byte[] encryptByPublicKeyByPKCS1Padding(byte[] data, String publicKey)
			throws Exception {
		byte[] keyBytes = org.apache.commons.codec.binary.Base64.decodeBase64(publicKey);
		X509EncodedKeySpec x509KeySpec = new X509EncodedKeySpec(keyBytes);
		KeyFactory keyFactory = KeyFactory.getInstance(KEY_ALGORITHM);
		Key publicK = keyFactory.generatePublic(x509KeySpec);
		// 对数据加密
		Cipher cipher = Cipher.getInstance("RSA/ECB/PKCS1Padding",BouncyCastleProvider.PROVIDER_NAME);
		cipher.init(Cipher.ENCRYPT_MODE, publicK);
		int inputLen = data.length;
		ByteArrayOutputStream out = new ByteArrayOutputStream();
		int offSet = 0;
		byte[] cache;
		int i = 0;
		// 对数据分段加密
		while (inputLen - offSet > 0) {
			if (inputLen - offSet > MAX_ENCRYPT_BLOCK) {
				cache = cipher.doFinal(data, offSet, MAX_ENCRYPT_BLOCK);
			} else {
				cache = cipher.doFinal(data, offSet, inputLen - offSet);
			}
			out.write(cache, 0, cache.length);
			i++;
			offSet = i * MAX_ENCRYPT_BLOCK;
		}
		byte[] encryptedData = out.toByteArray();
		out.close();
		return encryptedData;
	}

	public static String signSHA256RSA(String content, PrivateKey privateKey, String input_charset)
			throws Exception {
		if (privateKey == null) {
			throw new Exception("加密私钥为空, 请设置");
		}
		java.security.Signature signature = java.security.Signature.getInstance(SIGN_SHA256_WITH_RSA);
		signature.initSign(privateKey);
		signature.update(content.getBytes(input_charset));
		return Base64.encode(signature.sign());
	}

	public static String signSHA1RSA(String content, PrivateKey privateKey, String input_charset)
			throws Exception {
		if (privateKey == null) {
			throw new Exception("加密私钥为空, 请设置");
		}
		java.security.Signature signature = java.security.Signature.getInstance(SIGN_SHA1_WITH_RSA);
		signature.initSign(privateKey);
		signature.update(content.getBytes(input_charset));
		return Base64.encode(signature.sign());
	}

	public static void main(String[] args) {
		try {
			System.out.println(verifySHA256("accessNo=200000430311&goodsSubject=自定义套餐&mchNo=104440159122659&notifyUrl=https://payment.dev.ybm100.com/platform/chinabank/paySuccess&openId=okrF55DmFlN-zl89x_J_l0u4KoAM&outTransNo=1283947651494051912&productId=1066&requestNo=1284026384552820787&transAmount=1&transDate=20200717&transId=100&version=V1.0",
					"EIham6jJMAx0BuPQ8ksq65Ck6JeYN32jiowRNv/lbim6HeJ4KF+YvsNSNBGavnA4zs0GkEiWz9EG6CaKhhM+R1+1yEyIzVhLjLGbDZ0B+U57JmZWLeo5ReF8+o4nObs1WB4vvswfC41ngJ5x7rnYw0TaxR3aNvgfdLgYmkt/eu/QKppGfTl3CwvxxFpjjiwtDLD5cCRkrIlLrTXQ0D3jwqjrtxk0ZBrCfdCxeR8c9eJ/AbllGERalqc4Ow80bA63sGxGhjxmSIWZv1+G/HS5tSReSQyfXOL8SmOj468qel7QqCfHETPVLZF+3BCydDpooQFR+sZV7HAtk1HJdaCsJw==",
					RSAUtil.getPublicKey("MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAmWNa1/dXrsqd7u3VfFXN\n" +
							"RY1ZUWMe5Y9b5vzMilV/UD9z0QN6WUQBd7iltXlL67TpQ3Ixbcs02xY/WssFvvwr\n" +
							"dapv+GosJKG8KAR1OzvJm4TvUsup6XA301HRbnJFCjyXBS+wHBdHxhm68+hR+ejp\n" +
							"gUTARZAqUmgaY3nVu1e3LrAc3xf7zKTKRQGZMSoIRqnuniSkvK9Xyw4ga0Q2Tbzw\n" +
							"t2POIeLGXExQBk+OwjOOhm9N5jytJeySOQTxD8jCmzrX5u+3p+hinskisQY4+Wbs\n" +
							"nbr4FwOb7JllbnOj+9awwcPA+gennf56adJYkXB+Fis5kz0zxP2rVFLZqPYmUofc\n" +
							"ewIDAQAB"), "utf-8"));
		} catch (Exception e) {
			e.printStackTrace();
		}

	}
	
	public static boolean verifySHA256(String content, String sign, PublicKey publicKey, String inputCharset) {
		try {
			java.security.Signature signature = java.security.Signature.getInstance(SIGN_SHA256_WITH_RSA);
			signature.initVerify(publicKey);
			signature.update(content.getBytes(inputCharset));
			boolean bverify = signature.verify(Base64.decode(sign));
			return bverify;
		} catch (Exception e) {
			e.printStackTrace();
		}
		return false;
	}
	public static boolean verifySHA1(String content, String sign, PublicKey publicKey, String inputCharset) {
		try {
			java.security.Signature signature = java.security.Signature.getInstance(SIGN_SHA1_WITH_RSA);
			signature.initVerify(publicKey);
			signature.update(content.getBytes(inputCharset));
			boolean bverify = signature.verify(Base64.decode(sign));
			return bverify;
		} catch (Exception e) {
			e.printStackTrace();
		}
		return false;
	}

	
	public static PrivateKey getPrivateKey(String key) throws Exception {
		byte[] keyBytes = buildPKCS8Key(key);
		PKCS8EncodedKeySpec keySpec = new PKCS8EncodedKeySpec(keyBytes);
		KeyFactory keyFactory = KeyFactory.getInstance("RSA");
		PrivateKey privateKey = keyFactory.generatePrivate(keySpec);
		return privateKey;
	}
	
	private static byte[] buildPKCS8Key(String privateKey) throws IOException {
		if (privateKey.contains("-----BEGIN PRIVATE KEY-----")) {
			return Base64.decode(privateKey.replaceAll("-----\\w+ PRIVATE KEY-----", ""));
		} else if (privateKey.contains("-----BEGIN RSA PRIVATE KEY-----")) {
			final byte[] innerKey = Base64.decode(privateKey.replaceAll("-----\\w+ RSA PRIVATE KEY-----", ""));
			final byte[] result = new byte[innerKey.length + 26];
			System.arraycopy(Base64.decode("MIIEvAIBADANBgkqhkiG9w0BAQEFAASCBKY="), 0, result, 0, 26);
			System.arraycopy(BigInteger.valueOf(result.length - 4).toByteArray(), 0, result, 2, 2);
			System.arraycopy(BigInteger.valueOf(innerKey.length).toByteArray(), 0, result, 24, 2);
			System.arraycopy(innerKey, 0, result, 26, innerKey.length);
			return result;
		} else {
			return Base64.decode(privateKey);
		}
	}
	
	public static PublicKey getPublicKey(String key) throws Exception {
		if (key == null) {
			throw new Exception("加密公钥为空, 请设置");
		}
		key = key.replaceAll("\\-{5}[\\w\\s]+\\-{5}[\\r\\n|\\n]", "");
		byte[] buffer = Base64.decode(key);
		KeyFactory keyFactory = KeyFactory.getInstance("RSA");
		X509EncodedKeySpec keySpec = new X509EncodedKeySpec(buffer);
		return keyFactory.generatePublic(keySpec);
	}
}

